<?php 

	include_once $_SERVER["DOCUMENT_ROOT"].'/outils/string/StringUtils.php';
	include_once $_SERVER["DOCUMENT_ROOT"].'/outils/logger/Logger.php';
	include_once($_SERVER["DOCUMENT_ROOT"].'/outils/properties/PropertiesLoader.php');
	PropertiesLoader::loadProperties($_SERVER["DOCUMENT_ROOT"].'/properties.ini');
	class Database {
		var $host = null;
		var $login = null;
		var $password = null;
		var $bdd = null;
		var $pdo = null;
		static $database;
		
		
		
		static function getInstance() {
			if (self::$database == null) {
				self::$database = new Database;
			}
			return self::$database;
		}
		
		private function __construct() {}
		
		//TODO faire un module pour gérer les connexions (coder le mdp en base par la même occasion)
		function getPDO() {
			if ($this->pdo == null) {
				$connexion = 'mysql:host=' . $this->getHost() . ';dbname=' . $this->getBdd();
				$this->pdo = new PDO($connexion, $this->getLogin(), $this->getPassword());
			}
			return $this->pdo;
		}
		
		function getHost() {
			if ($this->host == null) {
				$this->host=PropertiesLoader::getProperty("bdd.host", true);
			}
			return $this->host;
		}
		
		function getLogin() {
			if ($this->login == null) {
				$this->login=PropertiesLoader::getProperty("bdd.login", true);
			}
			return $this->login;
		}
		
		function getPassword() {
			if ($this->password == null) {
				$this->password=PropertiesLoader::getProperty("bdd.password", true);
			}
			return $this->password;
		}
		
		function getBdd() {
			if ($this->bdd == null) {
				$this->bdd=PropertiesLoader::getProperty("bdd.bdd", true);
			}
			return $this->bdd;
		}
		
		function executeQuery($requete, $listeParametre = Array()) {
			if (!$this->isSelectQuery($requete)) {
				throw new Exception("La requête '$requete' n'est pas une requête de type 'SELECT'");
			}
			Logger::getLogger()->logInfo("Exécution de la requête select : ".$requete);
			$pdo = $this->getPDO();
			$result = $pdo->query($requete);
			if ($result === false) {
				throw new Exception("Erreur à l'exécution d'une requête : ".$pdo->errorInfo());
			}
			Logger::getLogger()->logInfo("Requête exécutée");
			return $result;
		}
		
		function executeQueryAndClose($requete, $listeParametre = Array()) {
			$result = $this->executeQuery($requete, $listeParametre = Array());
			$this->pdo = null;
			return $result;
		}
		
		function executeInsertQuery($requete) {
			if (!$this->isInsertQuery($requete)) {
				throw new Exception("La requête '$requete' n'est pas une requête d'insertion");
			}
			Logger::getLogger()->logInfo("Exécution de la requête insert : ".$requete);
			$pdo = $this->getPDO();
			$result = $pdo->exec($requete);
			if ($result === false) {
				$tabError = $pdo->errorInfo();
				throw new Exception("Erreur à l'exécution d'une requête d'insertion : ".$tabError[2]);
			}
			Logger::getLogger()->logInfo("Requête exécutée : ");
			return $pdo->lastInsertId();
		}
		
		function executeUpdateQuery($requete) {
			if (!$this->isUpdateQuery($requete)) {
				throw new Exception("La requête '$requete' n'est pas une requête de mise à jour");
			}
			Logger::getLogger()->logInfo("Exécution de la requête update : ".$requete);
			$pdo = $this->getPDO();
			$nbRow = $pdo->exec($requete);
			if ($nbRow === false) {
				$tabError = $pdo->errorInfo();
				throw new Exception("Erreur à l'exécution d'une requête d'update : ".$tabError[2]);
			}
			Logger::getLogger()->logInfo("Requête exécutée, nombre de lignes impactées : ".$nbRow);
			return $nbRow;
		}
		
		function executeStructureUpdateQuery($requete) {
			if (!$this->isStructureUpdateQuery($requete)) {
				throw new Exception("La requête '$requete' n'est pas une requête de mise à jour de structure");
			}
			Logger::getLogger()->logInfo("Exécution de la requête structure update : ".$requete);
			$pdo = $this->getPDO();
			$result = $pdo->exec($requete);
			if ($result === false) {
				$tabError = $pdo->errorInfo();
				throw new Exception("Erreur à l'exécution d'une requête d'update de structure : ".$tabError[2]);
			}
			Logger::getLogger()->logInfo("Requête exécutée");
			return $result;
		}
		
		
		function executeUpdateQueryAndClose($requete) {
			$nbRow = $this->executeUpdateQuery($requete);
			$this->pdo = null;
			return $nbRow;
		}
		
		function executeQueryListInTransaction($listeRequete) {
			$pdo = $this->getPDO();
			$pdo->beginTransaction();
			try {
				foreach ($listeRequete as $requete) {
					if ($this->isStructureUpdateQuery($requete)) {
						$this->executeStructureUpdateQuery($requete);
					} else if ($this->isInsertQuery($requete)) {
						$this->executeInsertQuery($requete);
					} else if ($this->isUpdateQuery($requete)){
						$this->executeUpdateQuery($requete);
					} else {
						throw new Exception ("Le type de requête '$requete' n'est pas reconnu");
					}
				}
			} catch (PDOException $e) {
				$pdo->rollback();
				//return $pdo->errorInfo();
				throw $e;
			}
			$pdo->commit();
			//return true;
		}
		
		function isInsertQuery($requete) {
			return StringUtils::startsWith($requete, "INSERT", false, true);
		}
		
		function isSelectQuery($requete) {
			return StringUtils::startsWith($requete, "SELECT", false, true);
		}
		
		function isUpdateQuery($requete) {
			return StringUtils::startsWith($requete, "UPDATE", false, true) ||
					StringUtils::startsWith($requete, "DELETE", false, true);
		}
		
		function isStructureUpdateQuery($requete) {
			return StringUtils::startsWith($requete, "CREATE TABLE", false, true) ||
					StringUtils::startsWith($requete, "UPDATE TABLE", false, true) ||
					StringUtils::startsWith($requete, "DROP", false, true);
		}
		
	}
?>